/*---------------------------------------------------------------------------------------
Filename: shaders.c
Description: Contains GLES2.0 code for shaders and the like.  Handles presets.

Copyright (c) 2010, droidViz Project Maintainers
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------------------*/
#include <stdlib.h>
#include "shaders.h"
#include "app.h"

// Default shaders - Passthrough
GLbyte *vPassthroughShader;

GLbyte vPassthroughShaderPresetWhite[] = 
	"attribute vec4 vPosition;         \n"
    "attribute vec4 vColor;            \n"
    "uniform int Velocity;             \n"
    "varying vec4 fColor;              \n"
    "void main()                       \n"
    "{                                 \n"
	"if( Velocity != 0 )               \n"
	"	fColor = vec4(0.2, 0.2, 0.2, 0.2); \n"
	"else                              \n"
	"	fColor = vColor;	           \n"
	"gl_Position = vPosition;          \n"
    "}		                           \n";

GLbyte vPassthroughShaderPreset[] = 
	"attribute vec4 vPosition;						\n"
	"attribute vec4 vColor;							\n"
	"uniform int Velocity;							\n"
	"varying vec4 fColor;							\n"
	"void main()									\n"
	"{												\n"
	"	//if( Velocity != 0 )						\n"
	"	//fColor = vColor;							\n"
	"		fColor[0] = vColor[0]*(0.5*vPosition[1]);		\n"
	"		fColor[1] = vColor[1]*(0.8*vPosition[2]);		\n"
	"		fColor[2] = vColor[2]*(0.7*vPosition[3]);		\n"
	"		fColor[3] = vColor[3]*(0.9*vPosition[0]);		\n"
	"	gl_Position = vPosition;					\n"
	"}												\n";


GLbyte *fPassthroughShader;

GLbyte fPassthroughShaderPreset[] = 
	"precision mediump float;						\n"
	"varying vec4 fColor;							\n"
	"void main()									\n"
	"{												\n"
	"	gl_FragColor = fColor;						\n"
	"}												\n";


GLuint program_1, program_2;
GLuint vertexShaderWhite_global, vertexShader_global;

// Check and print any GL error
void checkGlError( const char* op ) 
{
	GLint error;
    for( error = glGetError(); error; error = glGetError() ) 
        errprintf( "after %s() glError (0x%x)\n", op, error );
}

// Load and compile a shader, return 0 if error, or handle if success
GLuint LoadShader( GLenum type, const char *shaderSrc )
{
	GLuint shader;
	GLint compiled;
	GLint infoLen = 0;
	char* infoLog = NULL;

	// Create the shader object
	shader = glCreateShader( type );
	if( shader == 0 )
		return 0;

	// Load the shader source
	glShaderSource( shader, 1, &shaderSrc, NULL );

	// Compile the shader
	glCompileShader( shader );

	// Check the compile status
	glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled );
	if( !compiled )
	{
		// Shit, we didn't compile.  Let's log the errors.
		glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &infoLen );
		if( infoLen > 1 )
		{
			infoLog = malloc( sizeof( char ) * ( int )infoLen );
			glGetShaderInfoLog( shader, infoLen, NULL, infoLog );
			dprintf(0, "Error compiling shader %d:\n%s\n", type, infoLog );
			free( infoLog );
		}
		glDeleteShader( shader );
		shader = 0;
	}

	// All is well, return the handle to the shader
	return shader;
}

// Create and return a vertex/fragment program
GLuint CreateProgram( const char* pVertexSource, const char* pFragmentSource ) 
{
	GLuint vertexShader, pixelShader, program;
	GLuint vertexShaderWhite;
	GLint linkStatus = GL_FALSE, bufLength = 0;
	char* buf = NULL;
    
	// Load and compile the vertex shader
	vertexShader = LoadShader( GL_VERTEX_SHADER, pVertexSource );
    if ( !vertexShader )
        return 0;

	// Load and compile the fragment shader
    pixelShader = LoadShader( GL_FRAGMENT_SHADER, pFragmentSource );
    if ( !pixelShader )
        return 0;

	// Compile Another Static Shader for Use
	// Load and compile the vertex shader
	vertexShaderWhite = LoadShader( GL_VERTEX_SHADER, vPassthroughShaderPresetWhite );
    if ( !vertexShaderWhite )
        return 0;
	
	vertexShaderWhite_global = vertexShaderWhite;
	vertexShader_global = vertexShader;
	
	// Create Another Static Shader for Use
    program = glCreateProgram();
    if( program ) 
	{
		// We want to attach the shader to the program
        glAttachShader( program, vertexShaderWhite );
        checkGlError( "glAttachShader" );
        glAttachShader( program, pixelShader );
        checkGlError( "glAttachShader" );

		// Attempt to link the program and check for errors
        glLinkProgram( program );
        glGetProgramiv( program, GL_LINK_STATUS, &linkStatus );
        if( linkStatus != GL_TRUE ) 
		{
			// Thats NO good.
            glGetProgramiv( program, GL_INFO_LOG_LENGTH, &bufLength );
            if( bufLength ) 
			{
                buf = ( char* ) malloc( ( int )bufLength );
                if( buf )
				{
                    glGetProgramInfoLog( program, bufLength, NULL, buf );
                    dprintf( 0, "Could not link program:\n%s\n", buf );
                    free( buf );
                }
            }
            glDeleteProgram( program );
            program = 0;
        }
    }
	program_2 = program;

	// Create a shader program from these shaders
    program = glCreateProgram();
    if( program ) 
	{
		// We want to attach the shader to the program
        glAttachShader( program, vertexShader );
        checkGlError( "glAttachShader" );
        glAttachShader( program, pixelShader );
        checkGlError( "glAttachShader" );

		// Attempt to link the program and check for errors
        glLinkProgram( program );
        glGetProgramiv( program, GL_LINK_STATUS, &linkStatus );
        if( linkStatus != GL_TRUE ) 
		{
			// Thats NO good.
            glGetProgramiv( program, GL_INFO_LOG_LENGTH, &bufLength );
            if( bufLength ) 
			{
                buf = ( char* ) malloc( ( int )bufLength );
                if( buf )
				{
                    glGetProgramInfoLog( program, bufLength, NULL, buf );
                    dprintf( 0, "Could not link program:\n%s\n", buf );
                    free( buf );
                }
            }
            glDeleteProgram( program );
            program = 0;
        }
    }
	
	// All is well, return vertex/fragment program.
	program_1 = program;
    return program;
}

GLuint ChangeShader(int shader_code) 
{
	if (shader_code == 1)
	{
	// Create a shader program from these shaders
	glDetachShader( program_1, vertexShader_global);
	    checkGlError( "glDetachShader" );
	glAttachShader( program_1, vertexShaderWhite_global );
	    checkGlError( "glAttachShader" );
    //glUseProgram(program_2);
    //checkGlError( "glUseProgram" );
	dprintf(0,"Shader Code = 1");
	}

	else
	{
	// Create a shader program from these shaders
	// Grab the shader attributes and uniforms
	glDetachShader( program_1, vertexShaderWhite_global);
	    checkGlError( "glDetachShader" );
	glAttachShader( program_1, vertexShader_global );
	    checkGlError( "glAttachShader" );
     //glUseProgram(program_1);
	 //checkGlError( "glUseProgram" );
	dprintf(0,"Shader Code = 2");
	}
}

